package com.ruoyi.framework.web.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.model.AppleTokenPayload;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;

/**
 * Apple Token验证服务
 *
 * @author ruoyi
 */
@Service
public class AppleTokenVerificationService
{
    private static final Logger log = LoggerFactory.getLogger(AppleTokenVerificationService.class);

    /**
     * Apple公钥URL
     */
    private static final String APPLE_PUBLIC_KEYS_URL = "https://appleid.apple.com/auth/keys";

    /**
     * Apple发行者
     */
    private static final String APPLE_ISSUER = "https://appleid.apple.com";

    private final RestTemplate restTemplate;

    public AppleTokenVerificationService()
    {
        this.restTemplate = new RestTemplate();
    }

    /**
     * 验证Apple Identity Token
     *
     * @param identityToken Apple Identity Token
     * @return Apple用户信息
     * @throws Exception 验证失败时抛出异常
     */
    public AppleTokenPayload verifyAppleToken(String identityToken) throws Exception
    {
        log.info("开始验证Apple Identity Token");

        try
        {
            // 1. 获取Apple公钥
            JSONObject keys = getApplePublicKeys();

            // 2. 解析JWT header获取kid (Key ID)
            String[] chunks = identityToken.split("\\.");
            if (chunks.length != 3)
            {
                throw new IllegalArgumentException("Invalid JWT format");
            }

            String header = new String(Base64.getUrlDecoder().decode(chunks[0]));
            JSONObject headerJson = JSON.parseObject(header);
            String kid = headerJson.getString("kid");
            String alg = headerJson.getString("alg");

            log.info("JWT Header - kid: {}, alg: {}", kid, alg);

            // 3. 找到对应的公钥
            PublicKey publicKey = findAndBuildPublicKey(keys, kid);

            // 4. 验证JWT签名并解析Claims
            Claims claims = Jwts.parser()
                    .setSigningKey(publicKey)
                    .parseClaimsJws(identityToken)
                    .getBody();

            log.info("JWT Claims解析成功 - sub: {}, iss: {}, aud: {}",
                    claims.getSubject(), claims.getIssuer(), claims.getAudience());

            // 5. 验证issuer
            if (!APPLE_ISSUER.equals(claims.getIssuer()))
            {
                throw new SecurityException("Invalid issuer: " + claims.getIssuer());
            }

            // 6. 验证token是否过期
            if (claims.getExpiration() != null && claims.getExpiration().getTime() < System.currentTimeMillis())
            {
                throw new SecurityException("Token has expired");
            }

            // 7. 构建并返回Apple用户信息
            AppleTokenPayload payload = new AppleTokenPayload();
            payload.setSub(claims.getSubject());
            payload.setEmail(claims.get("email", String.class));
            payload.setEmailVerified(claims.get("email_verified", Boolean.class));
            payload.setIss(claims.getIssuer());
            payload.setAud((String) claims.getAudience());
            payload.setExp(claims.getExpiration() != null ? claims.getExpiration().getTime() / 1000 : null);
            payload.setIat(claims.getIssuedAt() != null ? claims.getIssuedAt().getTime() / 1000 : null);

            log.info("Apple Token验证成功 - Apple User ID: {}", payload.getSub());
            return payload;

        }
        catch (Exception e)
        {
            log.error("Apple Token验证失败: {}", e.getMessage(), e);
            throw new SecurityException("Apple Token验证失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取Apple公钥
     *
     * @return Apple公钥JSON
     */
    private JSONObject getApplePublicKeys()
    {
        try
        {
            log.info("正在获取Apple公钥...");
            String response = restTemplate.getForObject(APPLE_PUBLIC_KEYS_URL, String.class);
            JSONObject keys = JSON.parseObject(response);
            log.info("Apple公钥获取成功，包含 {} 个密钥", keys.getJSONArray("keys").size());
            return keys;
        }
        catch (Exception e)
        {
            log.error("获取Apple公钥失败: {}", e.getMessage(), e);
            throw new RuntimeException("Failed to fetch Apple public keys", e);
        }
    }

    /**
     * 根据kid查找并构建公钥
     *
     * @param keys Apple公钥JSON
     * @param kid  Key ID
     * @return RSA公钥
     * @throws Exception 构建失败时抛出异常
     */
    private PublicKey findAndBuildPublicKey(JSONObject keys, String kid) throws Exception
    {
        JSONArray keyArray = keys.getJSONArray("keys");

        for (int i = 0; i < keyArray.size(); i++)
        {
            JSONObject key = keyArray.getJSONObject(i);
            if (kid.equals(key.getString("kid")))
            {
                return buildRSAPublicKey(key.getString("n"), key.getString("e"));
            }
        }

        throw new SecurityException("Unable to find public key with kid: " + kid);
    }

    /**
     * 构建RSA公钥
     *
     * @param nStr modulus (Base64 URL编码)
     * @param eStr exponent (Base64 URL编码)
     * @return RSA公钥
     * @throws Exception 构建失败时抛出异常
     */
    private PublicKey buildRSAPublicKey(String nStr, String eStr) throws Exception
    {
        byte[] nBytes = Base64.getUrlDecoder().decode(nStr);
        byte[] eBytes = Base64.getUrlDecoder().decode(eStr);

        BigInteger modulus = new BigInteger(1, nBytes);
        BigInteger exponent = new BigInteger(1, eBytes);

        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory factory = KeyFactory.getInstance("RSA");

        return factory.generatePublic(spec);
    }
}